﻿
using System.Collections;
using System.Configuration;
using Microsoft.Interop.Security.AzRoles;
using System.Security.Principal;
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;


namespace AzMan.WebService
{

	public class AuthorizationManagerProvider
	{
		private readonly string storeLocation;
		private readonly string applicationName;
		private readonly object contextLock = new object();

		#region Constructor
		public AuthorizationManagerProvider(string storeLocation, string applicationName)
		{
			this.storeLocation = storeLocation;
			this.applicationName = applicationName;
		} 
		#endregion


		public string[] AvailableOperations(IPrincipal principal)
		{
			if (principal == null) throw new ArgumentNullException("principal");

			WindowsIdentity winIdentity = principal.Identity as WindowsIdentity;
			if (winIdentity == null)
			{
				throw new ArgumentException(Properties.Resource.WindowsIdentityOnly);
			}

			IAzApplication azApp;
			IAzClientContext azClientContext = GetClientContext(winIdentity, this.applicationName, out azApp);

			return AvailableOperations(azApp, azClientContext);

		}
		public string[] AvailableOperations(IAzApplication azApp, IAzClientContext azClientContext)
		{
			IAzClientContext client = azClientContext;
			try
			{
				//Creating two dictionaries
				Dictionary<string, int> opToId =  new Dictionary<string, int>(azApp.Operations.Count);
				Dictionary<int, string> idToOp =new Dictionary<int, string>(azApp.Operations.Count);
				foreach (IAzOperation op in azApp.Operations)
				{
					opToId.Add(op.Name, op.OperationID);
					idToOp.Add(op.OperationID, op.Name);
					Marshal.ReleaseComObject(op);
				}

				List<string> availableOps = new List<string>();

				object[] scope = new object[] { (object)"" };

				object[] operations = new object[idToOp.Count];
				int i = 0;
				try
				{
					foreach (int opId in idToOp.Keys)
					{
						operations[i] = (object)opId;
						i++;
					}
				}
				catch (COMException ex)
				{
					throw new InvalidOperationException("Failed", ex);
				}
				object[] results = (object[])client.AccessCheck("User authentication", scope,
					 operations, null, null, null, null, null);

				for (int j = 0; j < results.Length; j++)
				{
					if ((int)results[j] == 0)
					{
						availableOps.Add(idToOp[(int)operations[j]]);
					}
				}
				return availableOps.ToArray();
			}
			finally
			{
				Marshal.ReleaseComObject(client);
				Marshal.ReleaseComObject(azApp);
			}

		}

		private IAzClientContext GetClientContext(WindowsIdentity identity, String applicationName, out IAzApplication azApp)
		{
			lock (contextLock)
			{
				AzAuthorizationStoreClass store = new AzAuthorizationStoreClass();
				store.Initialize(0, this.storeLocation, null);
				azApp = store.OpenApplication(applicationName, null);
			}

			ulong tokenHandle = (ulong)identity.Token.ToInt64();
			IAzClientContext clientCtx = azApp.InitializeClientContextFromToken(tokenHandle, null);
			return clientCtx;
		}
	}

}